package org.andao.security.service.impl;

import java.io.Serializable;
import java.security.NoSuchAlgorithmException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;

import org.andao.core.base.service.BaseServiceImpl;
import org.andao.core.cache.EhCacheManager;
import org.andao.core.dao.helper.HibernateHelper;
import org.andao.core.dao.helper.Page;
import org.andao.core.dao.jdbc.JdbcSupportDao;
import org.andao.core.exception.ServiceException;
import org.andao.core.utils.EncryptUtils;
import org.andao.core.utils.ExCollectionUtils;
import org.andao.core.utils.WrappedRequest;
import org.andao.security.cache.CacheSecManager;
import org.andao.security.model.Resource;
import org.andao.security.model.Role;
import org.andao.security.model.User;
import org.andao.security.model.UserAdaptor;
import org.andao.security.model.UserVo;
import org.andao.security.rest.AuthenticationResult;
import org.andao.security.rest.HttpRequestSiningHelper;
import org.andao.security.service.UserService;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.simple.ParameterizedRowMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;



/**
 * 系统安全权限-用户管理服务. 
 * 
 * @author Marco.hu(hzg139@163.com)
 */
@Service("userService")
@Transactional
public class UserServiceImpl extends BaseServiceImpl<User> implements UserService{
	
	@Autowired
	@Qualifier("defaultJdbcSupportDao")
	private JdbcSupportDao jdbcSupportDao;
	
	/*
	 * 保存用户
	 */	
	@Override
	public User save(User user) throws ServiceException {			
		//插入缓存
		EhCacheManager.getCache(CacheSecManager.CACHE_SEC_USERS).put(user.getResourceid(), user);
		exGeneralHibernateDao.save(user);
		return get(user.getResourceid());
	}
		
	/*
	 * 更新	
	 */
	@Override
	public void update(User user) throws ServiceException{
		exGeneralHibernateDao.update(user);		
		EhCacheManager.getCache(CacheSecManager.CACHE_SEC_USERS).update(user.getResourceid(), user);
	}
	
	@Override
	public void saveOrUpdate(User user) throws ServiceException{
		exGeneralHibernateDao.saveOrUpdate(user);	
		EhCacheManager.getCache(CacheSecManager.CACHE_SEC_USERS).update(user.getResourceid(), user);
	}
	
	/*
	 * 根据用户登录ID获取用户
	 */
	@Transactional(readOnly=true)
	public User getUserByLoginId(String userName) throws ServiceException {		
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("username", userName);
		map.put("isDeleted", 0);
		//查用户名
		User user = (User) exGeneralHibernateDao.findUnique("from "+User.class.getName()+" where username = :username  and isDeleted=:isDeleted",map);
		if( null != user){
			return user;
		}else{//如果用户名为空，再查昵称
			user = (User) exGeneralHibernateDao.findUnique("from "+User.class.getName()+" where customUsername = :username  and isDeleted=:isDeleted",map); //or customUsername = :username)
			return user;
		}		
	}
	
	/*
	 *	判断是否存在该用户账号的用户 	
	 */
	@Transactional(readOnly=true)
	public boolean isExistsUser(String userName) throws ServiceException {		
		if(null != getUserByLoginId(userName)){
			return true;
		}
		return false;
	}

	/*
	 * 根据用户登录名获取用户不同级别的授权资源
	 */
	@Transactional(readOnly = true)
	public List<Resource> getUserAuthoritys(String username,int resourceLevel) throws ServiceException{
		List<Resource> authsList = new ArrayList<Resource>();
		User user = getUserByLoginId(username);
		for (Role role : user.getRoles()) {//遍历角色
			for(Resource res : role.getAuthoritys()){//遍历角色授权资源	
				if(resourceLevel != 0 && resourceLevel == res.getResourceLevel()){
					authsList.add(res);	
				}							
			}
		}
		return authsList;
	}

	//根据条件查找用户
	@Transactional(readOnly = true)
	public Page findUserByCondition(Map<String, Object> condition, Page page) throws ServiceException {
		
		//objCriterion.setFetchMode("userExtends", FetchMode.LAZY);
		Map<String,Integer> fetchMode = new HashMap<String,Integer>();
		fetchMode.put("userExtends", HibernateHelper.LAZY);
		List<Criterion> objCriterion = new ArrayList<Criterion>();
		if(condition.containsKey("userName")){//用户名
			objCriterion.add(Restrictions.like("username","%"+condition.get("userName")+"%"));
		}
		if(condition.containsKey("cnName")){//资源名称
			objCriterion.add(Restrictions.like("cnName","%"+condition.get("cnName")+"%"));
		}
		if(condition.containsKey("unitId")){//组织id
			objCriterion.add(Restrictions.eq("orgUnit.resourceid",condition.get("unitId")));
		}
		if(condition.containsKey("unitType")){//组织类型
			objCriterion.add(Restrictions.eq("orgUnit.unitType",condition.get("unitType")));
		}
		if(condition.containsKey("userType")){//用户类型
			objCriterion.add(Restrictions.eq("userType", condition.get("userType")));
		}
		//if(condition.containsKey("isDeleted")){//是否删除 =0
			objCriterion.add(Restrictions.eq("isDeleted", 0));
		//}
		if (condition.containsKey("enabled")) {//账号是否禁用
			objCriterion.add(Restrictions.eq("enabled", condition.get("enabled")));
		}
		if(condition.containsKey("filterList")){//过滤的账号
			objCriterion.add(Restrictions.not(Restrictions.in("username", (Collection<?>)condition.get("filterList"))));
		}
		return exGeneralHibernateDao.findByCriteria(User.class, page,fetchMode, objCriterion.toArray(new Criterion[objCriterion.size()]));
	
	}
		
	/*
	 * 删除
	 */
	@Override
	public void delete(User user) throws ServiceException{
		//删除的同时，将其名字修改成随机，以防添加时报重复的错误
		user.setUsername(user.getUsername()+"_DEL"+new Random().nextInt(10000));
		exGeneralHibernateDao.delete(user);
		//从缓存中移除
		EhCacheManager.getCache(CacheSecManager.CACHE_SEC_USERS).remove(user.getResourceid());
	}

	//批量删除
	@Override
	public void batchCascadeDelete(String[] ids) {
		if(ids.length>0){
			for(int index=0;index<ids.length;index++){
				delete(get(ids[index]));
			}
		}
	}
			
	@Override
	public AuthenticationResult determineRESTRequest(WrappedRequest request) {
		String sentSignature = HttpRequestSiningHelper.getSignature(request);//获取请求的签名
		// username:secretKey
        String[] split = sentSignature.split(":");
        String username = split[0];
        
        //根据username获取用户密码，根据密码生成的签名进行校验
        String secretKey = getSecretKey(username);
        if (secretKey == null) {
            return AuthenticationResult.failure();
        }
        if (HttpRequestSiningHelper.checkRequest(request, secretKey)) {
            return AuthenticationResult.sucess(username);
        }
        return AuthenticationResult.failure();
	}

	private String getSecretKey(String username){
		User user = getUserByLoginId(username);		
		return (null != user) ? user.getPassword() : null;
	}
	
	/*
	 * 用户对象适配，用于工作流	 
	 */
	public UserAdaptor getUserAdaptor(String userId) throws ServiceException {
		User user = this.get(userId);
		if(null != user){
			UserAdaptor userAdaptor = new UserAdaptor();
			if(null != user.getRoles()) {
				String[] roleIdArr = new String[user.getRoles().size()];
				int i = 0;
				for(Role role : user.getRoles()) {
					roleIdArr[i++] = role.getResourceid();
				}
				userAdaptor.setRoleIdArr(roleIdArr);
			}
			if(null != user.getOrgUnit()) {
				userAdaptor.setDeptIdArr(new String[] {user.getOrgUnit().getResourceid()});
			}
			
			
			userAdaptor.setId(user.getResourceid());
			userAdaptor.setName(user.getCnName());
			return userAdaptor;
		}
		return null;
	}


	//修改用户密码
	@Override
	public void changedUserPassword(String userId, String oldPwd, String newPwd) throws ServiceException {
		User user = get(userId);
		if(null == user)
			throw new ServiceException("没有找到用户："+userId);
		try {
			if(!user.getPassword().equals(EncryptUtils.MD5Encode(oldPwd))){
				throw new ServiceException("旧密码不正确");
			}			
			user.setPassword(EncryptUtils.MD5Encode(newPwd));
		} catch (NoSuchAlgorithmException e) {
			//noting
		}
		update(user);
		
	}

	//用户角色列表
	@Override
	@Transactional(readOnly=true)
	public List<Role> findUserRoles(String userId) throws ServiceException {
		User user = get(userId);
		if(null == user)
			throw new ServiceException("没有找到用户："+userId);
		
		return new ArrayList<Role>(user.getRoles());
	}

	@Override
	public boolean checkDuplicateName(String username, String resourceid) {
		List<User> duplicateUser = (List<User>) findByHql(User.class, "from " + User.class.getSimpleName()+" where username = ?  and resourceid <> ?", username, resourceid);
		return ExCollectionUtils.isNotEmpty(duplicateUser);
	}

	@Override
	public void delete(Serializable id) {
		User user = get(id);
		user.setUsername(user.getUsername()+"_DEL"+new Random().nextInt(10000));
		update(user);
		super.delete(id);
		this.clearAllCache();
	}

	@Override
	public void batchDelete(String[] ids) {
		for (String userId : ids) {
			delete(userId);
		}
	}

	@Override
	public void batchDelete(List<User> list) {
		for (User user : list) {
			delete(user.getResourceid());
		}
	}

	@Override
	public Page findUserBySqlCondition(Map<String, Object> condition, Page page) {

		StringBuffer sql = new StringBuffer("select u.resourceid,u.username,u.cnName,u.enabled,u.isDeleted,u.lastLoginTime,u.userType,u.loginIp,u.showOrder,u.photoURL,u.unitId as orgUnitId,org.unitName as orgUnit,group_concat(r.resourceid) as roleIds,group_concat(r.roleName) as roles");
		sql.append(" from seewo_sys_users as u");
		sql.append(" left join seewo_sys_unit as org on org.resourceid = u.unitId");
		sql.append(" left join seewo_sys_roleusers as ur on ur.userId = u.resourceid");
		sql.append(" left join seewo_sys_roles as r on ur.roleId = r.resourceid");
		sql.append(" where 1=1 ");

		MapSqlParameterSource parameters = new MapSqlParameterSource();

		if (condition.containsKey("isDeleted")) {
			sql.append(" and u.isDeleted = :isDeleted ");
			parameters.addValue("isDeleted", condition.get("isDeleted"));
		} else {
			sql.append(" and u.isDeleted = 0 ");
		}
		if (condition.containsKey("unitId")) {
			sql.append(" and u.unitId = :unitId");
			parameters.addValue("unitId", condition.get("unitId"));
		}
		if (condition.containsKey("unitIdList")) {
			sql.append(" and u.unitId in (:unitIdList)");
			@SuppressWarnings("unchecked")
			List<String> idsList = (List<String>) condition.get("unitIdList");
			if(idsList.isEmpty()){
				idsList.add("");//添加一个空的元素，防止报错
			}
			parameters.addValue("unitIdList", idsList);
		}
		if (condition.containsKey("userName")) {
			sql.append(" and u.userName like :_userName");
			parameters.addValue("_userName", "%" + condition.get("userName") + "%");
		}
		if (condition.containsKey("cnName")) {
			sql.append(" and u.cnName like :_cnName");
			parameters.addValue("_cnName", "%" + condition.get("cnName") + "%");
		}

		// group and order
		sql.append(" group by u.resourceid order by u.unitId asc, u.cnName asc");
		
		//The method below can not return the correct result because of the wrong definition of 'enabled' and 'isDeleted'
		//page = jdbcSupportDao.getBaseJdbcTemplate().findByMySqlCondition(UserVo.class,page, sql.toString(),parameters);
		
		page = jdbcSupportDao.getBaseJdbcTemplate().findByMySqlCondition(page, sql.toString(), new ParameterizedRowMapper<UserVo>() {
			@Override
			public UserVo mapRow(ResultSet rs, int rowNum) throws SQLException {
				UserVo vo = new UserVo(rs.getString("resourceid"), rs.getString("username"), rs.getString("cnName"), 
										rs.getBoolean("enabled"), rs.getBoolean("isDeleted"),rs.getDate("lastLoginTime"),
										rs.getString("loginIp"), rs.getString("userType"), rs.getString("photoURL"), 
										rs.getString("orgUnit"), rs.getString("orgUnitId"), rs.getString("roles"), 
										rs.getString("roleIds"), rs.getInt("showOrder"));
				return vo;
			}
		}, parameters);

		return page;
	}	
	
	

}
